namespace Caliburn.Micro
{
  using System;

  /// <summary>
  /// Hosts extension methods for <see cref="IScreen"/> classes.
  /// </summary>
  public static class ScreenExtensions
  {
    /// <summary>
    /// Activates the item if it implements <see cref="IActivate"/>, otherwise does nothing.
    /// </summary>
    /// <param name="potentialActivatable">The potential activatable.</param>
    public static void TryActivate(object potentialActivatable)
    {
      var activator = potentialActivatable as IActivate;
      if (activator != null)
        activator.Activate();
    }

    /// <summary>
    /// Deactivates the item if it implements <see cref="IDeactivate"/>, otherwise does nothing.
    /// </summary>
    /// <param name="potentialDeactivatable">The potential deactivatable.</param>
    /// <param name="close">Indicates whether or not to close the item after deactivating it.</param>
    public static void TryDeactivate(object potentialDeactivatable, bool close)
    {
      var deactivator = potentialDeactivatable as IDeactivate;
      if (deactivator != null)
        deactivator.Deactivate(close);
    }

    /// <summary>
    /// Closes the specified item.
    /// </summary>
    /// <param name="conductor">The conductor.</param>
    /// <param name="item">The item to close.</param>
    public static void CloseItem(this IConductor conductor, object item)
    {
      conductor.DeactivateItem(item, true);
    }

    /// <summary>
    /// Closes the specified item.
    /// </summary>
    /// <param name="conductor">The conductor.</param>
    /// <param name="item">The item to close.</param>
    public static void CloseItem<T>(this ConductorBase<T> conductor, T item)
    {
      conductor.DeactivateItem(item, true);
    }

    ///<summary>
    /// Activates a child whenever the specified parent is activated.
    ///</summary>
    ///<param name="child">The child to activate.</param>
    ///<param name="parent">The parent whose activation triggers the child's activation.</param>
    public static void ActivateWith(this IActivate child, IActivate parent)
    {
      EventHandler<ActivationEventArgs> handler = (s, e) => child.Activate();
      parent.Activated += handler;

      var deactivator = parent as IDeactivate;
      if (deactivator != null)
      {
        EventHandler<DeactivationEventArgs> handler2 = null;
        handler2 = (s, e) =>
        {
          if (e.WasClosed)
          {
            parent.Activated -= handler;
            deactivator.Deactivated -= handler2;
          }
        };
        deactivator.Deactivated += handler2;
      }
    }

    ///<summary>
    /// Deactivates a child whenever the specified parent is deactivated.
    ///</summary>
    ///<param name="child">The child to deactivate.</param>
    ///<param name="parent">The parent whose deactivation triggers the child's deactivation.</param>
    public static void DeactivateWith(this IDeactivate child, IDeactivate parent)
    {
      EventHandler<DeactivationEventArgs> handler = null;
      handler = (s, e) =>
      {
        child.Deactivate(e.WasClosed);
        if (e.WasClosed)
          parent.Deactivated -= handler;
      };
      parent.Deactivated += handler;
    }

    ///<summary>
    /// Activates and Deactivates a child whenever the specified parent is Activated or Deactivated.
    ///</summary>
    ///<param name="child">The child to activate/deactivate.</param>
    ///<param name="parent">The parent whose activation/deactivation triggers the child's activation/deactivation.</param>
    public static void ConductWith<TChild, TParent>(this TChild child, TParent parent)
      where TChild : IActivate, IDeactivate
      where TParent : IActivate, IDeactivate
    {
      child.ActivateWith(parent);
      child.DeactivateWith(parent);
    }
  }
}
